# Migrating from `v2` to `v3`

With [new major version](https://github.com/graphql-hive/envelop/pull/1487) comes breaking changes.
This section will guide you through the process of migrating from `v2` to `v3`.

## 1. Remove `graphql` as a peer dependency

We have designed the new `envelop` to be engine agnostic. This means that `graphql` is no longer a
peer dependency. You still want to use `graphql-js` but you can easily use any GraphQL Engine since
`envelop` now simply wraps the `parse`, `validate`, `execute` and `subscribe` functions that you
provide.

```diff
- import { envelop } from '@envelop/core';
+ import { envelop, useEngine } from '@envelop/core';
+ import * as GraphQLJS from 'graphql'

- const getEnveloped = envelop([ ... ])
+ const getEnveloped = envelop({ plugins: [ useEngine(GraphQLJS), ... ] })
```

## 2. Removed orchestrator tracing

`GraphQLSchema` was wrapped to provide resolvers/fields tracing from the schema. Issue with this
approach was it was very specific to the underlying engine's implementation. With the new version we
no longer want to depend to a specific implementation. Now users can wrap their schemas and add
tracing themselves.

### 1. Removed `onResolverCalled`

We decided to drop `onResolverCalled` hook and instead
[provide a new plugin](https://github.com/graphql-hive/envelop/pull/1500) that will let you hook
into this phase.

```diff
import { parse, validate, specifiedRules,execute, subscribe } from 'graphql'
import { envelop, Plugin, useEngine } from '@envelop/core'
+ import { useOnResolve } from '@envelop/on-resolve'

import { onResolverCalled } from './my-resolver'

function useResolve(): Plugin {
  return {
-   onResolverCalled: onResolverCalled,
+   onPluginInit: ({ addPlugin }) => {
+     addPlugin(useOnResolve(onResolverCalled))
+   },
  }
}

const getEnveloped = envelop({
  plugins: [
    useEngine({ parse, validate,specifiedRules, execute, subscribe }),
    // ... other plugins ...
    useResolve(),
  ],
});
```

### 2. Drop `useTiming` plugin

This plugin was dependent on tracing the schema. As we no longer support wrap the schema out of the
box we decided to drop this plugin.

At this moment we do not have any alternative. We recommend using a
[tracing solution](/v3/guides/monitoring-and-tracing).

## 3. Remove `EnvelopError`

To keep the core agnostic from a specific implementation we no longer provide the `EnvelopError`
class. To ensure an error is `GraphQLError` envelop check if it an `instanceOf Error` and the name
of error is `GraphQLError`. We provide a helper utility `isGraphQLError` to check if an error is a
`GraphQLError`.

```diff
- import {EnvelopError} from '@envelop/core'
+ import { GraphQLError } from 'graphql'

const main () => {
  try {
    // ...
  } catch (error) {
- throw EnvelopError(error)
+ throw GraphQLError(error)
  }
}
```

### 1.`@envelop/sentry` default will skip all `GraphQLError`

Since we no longer support `EnvelopError` it will skip sending any errors to sentry that are
`GraphQLError`.

## 4. Remove `isIntrospectionDocument` and `isIntrospectionQuery` utility

To keep core agnostic we recommend you create your own utility for this.

## 5. Remove `useAsyncSchema` plugin

This was a mistake from beginning as we cannot asynchronously `validate` and `parse` since with
[`graphql`](https://github.com/graphql/graphql-js) these functions are synchronous in nature.

You should first load your schema and then create the envelop instance and pass the schema to it.

```ts
import * as GraphQLJS from 'graphql'
import { envelop, useEngine, useSchema } from '@envelop/core'

// This assumes you are using Node v14.8+ where top-level await is supported
const schema = await loadSchema()

const getEnveloped = envelop({
  plugins: [useEngine(GraphQLJS), useSchema(schema)]
})
```

## 6. Rename `useLazyLoadedSchema` to `useSchemaByContext`

Original name was very misleading since lazy loading could mean it can be asynchronous in nature.
This plugin was renamed to better reflect its purpose. It is now called `useSchemaByContext`

## 7. Drop `enableIf` utility

This utility was used to enable plugins conditionally. For a better developer experience we have
dropped this utility and favor more type safe way to conditionally enable plugins.

```diff
- import { envelop, useMaskedErrors, enableIf } from '@envelop/core'
+ import { envelop, useMaskedErrors, useEngine } from '@envelop/core'
import * as GraphQLJS from 'graphql'

const isProd = process.env.NODE_ENV === 'production'

const getEnveloped = envelop({
 plugins: [
  useEngine(GraphQLJS),
  // This plugin is enabled only in production
-  enableIf(isProd, useMaskedErrors())
+  isProd && useMaskedErrors()
 ]
})
```

## 8. Update options for `useMaskedErrors` plugin

- We _removed_ `handleValidationErrors` and `handleParseErrors` options since ONLY masking
  validation errors OR ONLY disabling introspection errors does not make sense, as both can be
  abused for reverse-engineering the GraphQL schema (see
  https://github.com/nikitastupin/clairvoyance for reverse-engineering the schema based on
  validation error suggestions). Instead you should use `useErrorHandler` plugin where you can
  access each phase and decide what to do with the error.
- Renamed `formatError` to `maskError`

```diff
import { envelop, useMaskedErrors, useEngine, isGraphQLError } from '@envelop/core'
import * as GraphQLJS from 'graphql'

export const customFormatError: MaskError = err => {
  if (isGraphQLError(err)) {
    return new GraphQLError('Sorry, something went wrong.')
  }
  return err
}

const getEnveloped = envelop({
  plugins: [
    useEngine(GraphQLJS),
-   useMaskedErrors({ formatError: customFormatError })
+   useMaskedErrors({ maskError: customFormatError })
  ]
})
```

## 9. Drop support for Node.js v12

Node.js v12 is no longer supported by the Node.js team.
https://github.com/nodejs/Release/#end-of-life-releases
